﻿using System;
using System.Collections.Generic;
using System.Linq;
using Keyki.NefClass.Kernel.Fuzzy;
using Keyki.NefClass.Kernel.Fuzzy.Rulles;

namespace Keyki.NefClass.Kernel.Data
{
	/// <summary>
	/// Represent one feature from dataset (one column)
	/// default don't use PLINQ
	/// </summary>
	public sealed class Feature
	{
		#region Variables
		private readonly List<double> data;
		private List<LinguisticVariable> linguisticVariables;
		private String name;
		#endregion

		#region Constructor

		public Feature(String name)
			: this(name, false)
		{ }

		public Feature(String name, bool isParalel)
		{
			this.name = name;
			IsParalel = isParalel;
			data = new List<double>();
			linguisticVariables = new List<LinguisticVariable>();
		}//Feature

		#endregion

		#region Properties

		public double this[int index]
		{
			get
			{
				if (data == null)
					throw new NullReferenceException("Data list is null");

				if (data.Count <= index)
					throw new IndexOutOfRangeException();

				return data[index];
			} //get
			set
			{
				if (data == null)
					throw new NullReferenceException("Data list is null");

				if (data.Count <= index)
					throw new IndexOutOfRangeException();

				data[index] = value;
			} //set
		}//this[index]

		/// <summary>
		/// set use parallel algorithm or not
		/// true - enable PLINQ
		/// false - disable PLINQ, used LINQ
		/// </summary>
		public bool IsParalel { get; set; }

		/// <summary>
		/// Return Maximum value for feature data list
		/// </summary>
		public double Max
		{
			get
			{
				double max = double.NaN;

				if (data == null)
					throw new NullReferenceException("Data list is null");
				if (data.IsEmpty())
					throw new IndexOutOfRangeException("Data list cannot be empty");

				if (IsParalel)
				{
					max = data.AsParallel().Max();
				} //if IsParalel
				else
				{
					max = data.Max();
				} //else

				return max;
			} // get;
		}//Max

		/// <summary>
		/// Return Minimum value for feature data list
		/// </summary>
		public double Min
		{
			get
			{
				double min = double.NaN;

				if (data == null)
					throw new NullReferenceException("Data list is null");
				if (!data.Any())
					throw new IndexOutOfRangeException("Data list cannot be empty");

				if (IsParalel)
				{
					min = data.AsParallel().Min();
				} //if IsParalel
				else
				{
					min = data.Min();
				} //else

				return min;
			} // get;
		}//Min

		/// <summary>
		/// Return number of elements in Feature list
		/// </summary>
		public int Count
		{
			get { return data.Count; }
		}//Count

		/// <summary>
		/// Return number of elements in LinguisticVariable list
		/// </summary>
		public int CountLinguisticVariable
		{
			get { return linguisticVariables.Count; }
		}//CountLinguisticVariable


		#endregion

		#region Methods

		public void Add(double value)
		{
			data.Add(value);
		}//Add(double)

		public void AddRange(IEnumerable<double> collection)
		{
			data.AddRange(collection);
		}//AddRange

		public void AddLinguisticVariable(LinguisticVariable variable)
		{
			linguisticVariables.Add(variable);
		}//AddLinguisticVariable

		public void Remove(int index)
		{
			data.RemoveAt(index);
		}//Remove(int)

		public List<double> GetRange(int index, int count)
		{
			return data.GetRange(index, count);
		}//GetRange

		public LinguisticVariable GetAt(int index)
		{
			if (index > linguisticVariables.Count)
			{
				throw new IndexOutOfRangeException("No such linguistic variable");
			}

			return linguisticVariables[index];
		}//GetAt

		/// <summary>
		/// Return Feature with sorted from min to max 
		/// </summary>
		/// <returns>Feature with sorted data</returns>
		public Feature Sort()
		{
			Feature sorted = new Feature("sorted");

			sorted.AddRange(data);

			sorted.data.Sort();

			sorted.linguisticVariables = linguisticVariables;

			return sorted;
		}//Sort()

		public bool IsEmpty()
		{
			return data.IsEmpty();
		}//IsEmpty()

		public bool Any()
		{
			return data.Any();
		}//Any()

		#endregion

	}//Feature
}//Keyki.NefClass.Kernel.Classes